﻿//**************************************************
//Description:  元素系统
//Author:       leubooth
//Date:         2016.11.03
//**************************************************

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public class ItemSystem : MonoBehaviour
{
    /// <summary>
    /// 单件
    /// </summary>
    public static ItemSystem Instance;

    /// <summary>
    /// 元素预制
    /// </summary>
    public GameObject itemPrefab;

    /// <summary>
    /// 颜色列表
    /// </summary>
    public List<Color> colors = new List<Color>();

    /// <summary>
    /// 元素列表
    /// </summary>
    public List<Item> items = new List<Item>();

    /// <summary>
    /// 按照运动轨迹生成的元素列表
    /// </summary>
    public List<Item> orderItems = new List<Item>();

    void Awake()
    {
        Instance = this;

        //初始化颜色集合
        colors.Add(Color.red);
        colors.Add(new Color(255, 165, 0)/255);
        colors.Add(Color.yellow);
        colors.Add(Color.green);
        colors.Add(Color.blue);
        colors.Add(Color.magenta);
    }

    /// <summary>
    /// 初始化元素系统
    /// </summary>
    public void InitItemSystem()
    {
        //清空元素
        for (int index = 0; index < transform.childCount; index++)
        {
            Destroy(transform.GetChild(index).gameObject);
        }

        //初始化元素列表

        items.Clear();

        GameObject itemObj;
        Item item;

        for (int i = 0; i < GridSystem.Instance.countX; i++)
        {
            for (int j = 0; j < GridSystem.Instance.countY; j++)
            {
                itemObj = (GameObject)Instantiate(itemPrefab);
                itemObj.transform.parent = this.transform;
                itemObj.transform.position = new Vector3(i, j);
                itemObj.transform.localScale = new Vector3(0.9f, 0.9f, 0.9f);

                Color color = colors[Random.Range(0, colors.Count)];
                itemObj.GetComponent<MeshRenderer>().material.color = color;

                item = itemObj.GetComponent<Item>();
                item.x = i;
                item.y = j;
                item.color = color;

                items.Add(item);
            }
        }

        //初始化按轨迹排序后的元素列表

        orderItems.Clear();

        for (int m = 0; m < GridSystem.Instance.orderGrids.Count; m++)
        {
            int indexX = GridSystem.Instance.orderGrids[m].GetComponent<Grid>().x;
            int indexY = GridSystem.Instance.orderGrids[m].GetComponent<Grid>().y;

            orderItems.Add(items[indexX * GridSystem.Instance.countY + indexY]);
        }
    }

    //关闭列表，用来存储要被消除的元素
    public List<Item> closeList = new List<Item>();

    /// <summary>
    /// 递归计算item的可清除元素
    /// </summary>
    /// <param name="item"></param>
    public void Calculate(Item item)
    {
        //Debug.Log("将" + item.x + ":" + item.y + "标记为可消除");

        if (!closeList.Contains(item))
        {
            closeList.Add(item);
        }

        List<Item> neighbors = GetNeighbor(item);
        if (neighbors == null) return;
        foreach (Item tempItem in neighbors)
        {
            if (!closeList.Contains(tempItem) && tempItem.color == item.color)
            {
                Calculate(tempItem);
            }
        }
    }

    /// <summary>
    /// 刷新item，删除元素，刷新列表，元素运动
    /// </summary>
    public void Refresh()
    {
        if (closeList == null) return;

        switch (GridSystem.Instance.moveType)
        {
            case 0:
                #region
                //下落模式
                //复制临时列表
                List<Item> itemsCopy = new List<Item>();
                for (int a = 0; a < items.Count; a++)
                {
                    itemsCopy.Add(items[a]);
                }

                for (int i = 0; i < closeList.Count; i++)
                {
                    itemsCopy.Remove(closeList[i]);
                    Destroy(closeList[i].gameObject);
                }
                for (int j = 0; j < GridSystem.Instance.countX; j++)
                {
                    List<Item> tempItems = itemsCopy.FindAll(thisitem => thisitem.x == j);
                    if (tempItems.Count < GridSystem.Instance.countY)
                    {
                        tempItems.OrderBy(tempItem => tempItem.y);
                        for (int m = 0; m < tempItems.Count; m++)
                        {
                            tempItems[m].MoveToTarget(new Vector3(j, m));
                            items[j * GridSystem.Instance.countY + m] = tempItems[m];
                            orderItems[j * GridSystem.Instance.countY + m] = tempItems[m];
                        }
                        //补充新的元素
                        for (int n = tempItems.Count; n < GridSystem.Instance.countY; n++)
                        {
                            GameObject itemObj = (GameObject)Instantiate(itemPrefab);
                            itemObj.transform.parent = this.transform;
                            //为了给元素块有一个平滑的入场动画，将出生点按格子数向上做了修正 + GridSystem.Instance.countY - tempItems.Count
                            itemObj.transform.position = new Vector3(j, n + GridSystem.Instance.countY - tempItems.Count);
                            itemObj.transform.localScale = new Vector3(0.9f, 0.9f, 0.9f);

                            Color color = colors[Random.Range(0, colors.Count)];
                            itemObj.GetComponent<MeshRenderer>().material.color = color;

                            Item item = itemObj.GetComponent<Item>();
                            item.x = j;
                            item.y = n;
                            item.color = color;
                            item.MoveToTarget(new Vector3(j, n));
                            items[j * GridSystem.Instance.countY + n] = item;
                            orderItems[j * GridSystem.Instance.countY + n] = item;
                        }
                    }
                }
                #endregion
                break;
            case 1:
            case 2:
                //从orderItems中将closeList中的元素删除
                for (int i = 0; i < closeList.Count; i++)
                {
                    orderItems.Remove(closeList[i]);
                    Destroy(closeList[i].gameObject);
                }

                //对比orderGrids和orderItems
                for (int j = 0; j < orderItems.Count; j++)
                {
                    Item item = orderItems[j].GetComponent<Item>();
                    Grid grid = GridSystem.Instance.orderGrids[j].GetComponent<Grid>();

                    if (item.x != grid.x || item.y != grid.y)
                    {
                        //Debug.Log("该节点需要向下游移动");

                        //计算运动路径的起点和终点
                        Grid startGrid = GridSystem.Instance.orderGrids.Find(thisitem => thisitem.x == item.x && thisitem.y == item.y);
                        Grid endGrid = GridSystem.Instance.orderGrids[j].GetComponent<Grid>();

                        int startIndex = GridSystem.Instance.orderGrids.IndexOf(startGrid);
                        int endIndex = GridSystem.Instance.orderGrids.IndexOf(endGrid);

                        List<Vector3> path = new List<Vector3>();
                        for (int m = startIndex; m >= endIndex; m--)
                        {
                            Grid tmpGrid = GridSystem.Instance.orderGrids[m].GetComponent<Grid>();
                            path.Add(new Vector3(tmpGrid.x, tmpGrid.y));
                        }

                        orderItems[j].GetComponent<Item>().path = path;
                        orderItems[j].GetComponent<Item>().MoveToTargetByPath();

                        items[endGrid.x * GridSystem.Instance.countY + endGrid.y] = item;
                    }
                }

                //Debug.Log(GridSystem.Instance.orderGrids.Count - orderItems.Count);

                int num = orderItems.Count;
                int count = GridSystem.Instance.orderGrids.Count - orderItems.Count;

                //填充新的元素
                for (int n = 0; n < count; n++)
                {
                    GameObject itemObj = (GameObject)Instantiate(itemPrefab);
                    itemObj.transform.parent = this.transform;
                    itemObj.transform.position = GridSystem.Instance.bornPos;
                    itemObj.transform.localScale = new Vector3(0.9f, 0.9f, 0.9f);

                    Color color = colors[Random.Range(0, colors.Count)];
                    itemObj.GetComponent<MeshRenderer>().material.color = color;

                    Item item = itemObj.GetComponent<Item>();
                    Grid grid = GridSystem.Instance.orderGrids[num + n].GetComponent<Grid>();
                    item.x = grid.x;
                    item.y = grid.y;
                    item.color = color;

                    Grid startGrid = GridSystem.Instance.orderGrids.Find(thisitem => thisitem.x == (int)GridSystem.Instance.bornPos.x && thisitem.y == (int)GridSystem.Instance.bornPos.y);
                    Grid endGrid = grid;

                    int startIndex = GridSystem.Instance.orderGrids.IndexOf(startGrid);
                    int endIndex = GridSystem.Instance.orderGrids.IndexOf(endGrid);

                    List<Vector3> path = new List<Vector3>();
                    for (int m = startIndex; m >= endIndex; m--)
                    {
                        Grid tmpGrid = GridSystem.Instance.orderGrids[m].GetComponent<Grid>();
                        path.Add(new Vector3(tmpGrid.x, tmpGrid.y));
                    }

                    item.GetComponent<Item>().path = path;
                    item.GetComponent<Item>().MoveToTargetByPath();

                    orderItems.Add(item);
                    items[item.x * GridSystem.Instance.countY + item.y] = item;
                }
                break;
        }

        closeList.Clear();
        GameManager.Instance.state = GameState.Playing;
    }

    /// <summary>
    /// 获取某元素的邻居元素
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    List<Item> GetNeighbor(Item item)
    {
        List<Item> neighbors = new List<Item>();

        if (item != null)
        {
            int x = item.x;
            int y = item.y;

            if (x != 0)
            {
                neighbors.Add(items[(x - 1) * GridSystem.Instance.countY + y]);
            }
            if (x != GridSystem.Instance.countX - 1)
            {
                neighbors.Add(items[(x + 1) * GridSystem.Instance.countY + y]);
            }
            if (y != 0)
            {
                neighbors.Add(items[x * GridSystem.Instance.countY + y - 1]);
            }
            if (y != GridSystem.Instance.countY - 1)
            {
                neighbors.Add(items[x * GridSystem.Instance.countY + y + 1]);
            }
        }

        return neighbors;
    }
}